#include "stdafx.h"

#define EXP_FUN KYPHONEHIDDRV_API

#if defined(_DEBUG) && defined(_LIB__)
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#include <dbt.h>

#include <stdlib.h>
#include <stdio.h>


#include "KyPhoneHidDrv.h"
#include "UsbIo.h"
#include "Qunue.h"

#include "..\protocol\wjprotocol.h"
#include "setupapi.h"


#include "Hidsdi.h"



KY_USB_DEV  g_hUsbDevMap = {0,NULL,NULL,NULL,NULL};

#define USB_PATHINFO PSP_DEVICE_INTERFACE_DETAIL_DATA

void SendDetachMsgToParent(HANDLE);
int DevMounted(USB_PATHINFO pDevInfo);
int CheckPathInMount(char * szpath);
HANDLE MountDev(USB_PATHINFO pDevInfo, INT ChipId, HANDLE hRead, HANDLE hWrite);
HANDLE Get_DeviceHandle(GUID HidGuid, DWORD index,MC_HID_MODE mode,  USB_PATHINFO &Dev_info);

const HID_DRIVER* mDriverList[] = REGIST_DRIVER_LIST;


const HID_DRIVER* LoadDriver(WORD devVid, WORD devPid, WORD usagepage)
{
    DWORD devid = (devVid << 16) | devPid;
    for (int i = 0; i < sizeof(mDriverList) / sizeof(mDriverList[0]); i++)
    {
        const HID_DRIVER* pdrv = mDriverList[i];
        if (pdrv->vid == devVid) {
            for (int pidlist = pdrv->pid; pidlist <= ((pdrv->pid_end==0)? pdrv->pid : pdrv->pid_end); pidlist++) {
                if (pidlist == devPid && ( pdrv->HidUsagePage == 0 || pdrv->HidUsagePage == usagepage))
                    return pdrv;
            }
        }
    }
    return NULL;
}

const HID_DRIVER* LoadDriver(DWORD devid)
{
    for (int i = 0; i < sizeof(mDriverList) / sizeof(mDriverList[0]); i++) {
        if (mDriverList[i]->nDevTypeId == devid ) 
            return mDriverList[i];
    }    
    return NULL;
}
/********************************************************************/
/* Low Device enum*/
int Get_att_capab(HANDLE hCom, USHORT &InputReportLen, USHORT &OutputReportLen)
{
    HIDD_ATTRIBUTES HidAttributes;
    PHIDP_PREPARSED_DATA hidPreparsedData;
    HIDP_CAPS Capab;
    DWORD matchID = CHIP_UNKOWN;
    if( HidD_GetAttributes( hCom, &HidAttributes) &&
        HidD_GetPreparsedData( hCom, &hidPreparsedData))
    {
        NTSTATUS status = HidP_GetCaps( hidPreparsedData, &Capab);
        
        if (status == HIDP_STATUS_SUCCESS)
        {
            const HID_DRIVER* pdriver = LoadDriver(HidAttributes.VendorID, HidAttributes.ProductID, Capab.UsagePage);
            if( pdriver )
            {
                InputReportLen = Capab.InputReportByteLength;
                OutputReportLen = Capab.OutputReportByteLength;
                matchID = pdriver->nDevTypeId;
            }
        }
        HidD_FreePreparsedData( hidPreparsedData);
    }

    return matchID;
}

HANDLE Get_DeviceHandle(GUID HidGuid, DWORD index,MC_HID_MODE mode, USB_PATHINFO &Dev_info)
{
    HDEVINFO hDevInfo;
    DWORD requiredLength;
    SP_DEVICE_INTERFACE_DATA DevInterfaceData;
    
    hDevInfo = SetupDiGetClassDevs(&HidGuid,NULL,NULL,
        DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
    if(hDevInfo ==NULL )
    {
        return NULL;
    }
    
    DevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
    BOOL bSuccess = SetupDiEnumDeviceInterfaces(hDevInfo,NULL,&HidGuid,index,
        &DevInterfaceData);
    if (!bSuccess)
    {
        SetupDiDestroyDeviceInfoList(hDevInfo);
        return HANDLE_LAST_DEVICE;
    }

    SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, NULL, 0, 
        &requiredLength, NULL);
    Dev_info=(PSP_INTERFACE_DEVICE_DETAIL_DATA) new BYTE[requiredLength]; 
    Dev_info->cbSize =sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);

    
    if( !SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevInterfaceData, 
                    Dev_info, requiredLength, NULL, NULL) 
					||( mode == MC_HID_WRITE_WITH_INFO ) && DevMounted(Dev_info) )//check device has been mount in device map Only when open mode is READ 
    {
        SetupDiDestroyDeviceInfoList(hDevInfo);
        delete Dev_info;
        return NULL;
    }

    HANDLE hFindDevice;
    if( mode == MC_HID_READ )
    {
        hFindDevice = CreateFile((LPCSTR)Dev_info->DevicePath, GENERIC_READ, \
                            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, \
                            FILE_FLAG_OVERLAPPED, NULL); 
    }
    else
    {
        hFindDevice = CreateFile((LPCSTR)Dev_info->DevicePath, GENERIC_READ|GENERIC_WRITE, \
                            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, \
                            FILE_FLAG_OVERLAPPED, NULL); 
    }

    if (hFindDevice ==INVALID_HANDLE_VALUE)
    {
        CloseHandle(hFindDevice);
        SetupDiDestroyDeviceInfoList(hDevInfo);
        delete Dev_info;
        return NULL;
    }

    SetupDiDestroyDeviceInfoList(hDevInfo);
	if( mode != MC_HID_WRITE_WITH_INFO )
		delete Dev_info;

    return hFindDevice;
}

static HANDLE Get_device(HANDLE &hCom, int * pChipId,
                         USHORT *InputReportLen, USHORT *OutputReportLen, MC_HID_MODE mode)
{
    GUID HidGuid;
    DWORD index = 0;
    HidD_GetHidGuid( &HidGuid);
	USB_PATHINFO Dev_info;
    
    while(1)
    {
        hCom = Get_DeviceHandle(HidGuid, index++, mode,  Dev_info);
        if( hCom==HANDLE_LAST_DEVICE) //LastDevice
            return NULL;

        if( hCom == NULL ) 	continue;
        int dev_id = Get_att_capab( hCom, *InputReportLen, *OutputReportLen);

        if( dev_id != CHIP_UNKOWN)
        {
            *pChipId = dev_id;
			return Dev_info;
        }
        delete Dev_info;
        CloseHandle(hCom);
    }
    return NULL;
}

/* R/W Device */
/********************************************************************/

/* Low Level Device Interface*/
/*****************************************************
*  Read function, 
*****************************************************/
void MyTrace(const char * fmt, ...) 
{
#ifdef _DEBUG
    #pragma message("****************\n* Win32 DEBUG \n") 
#else
    #pragma message("****************\n* Win32 Release \n") 
#endif
#if 0//ndef __DEBUG
    #pragma message("----------------\n* No trace version\n****************") 
    return;
#else
    #pragma message("----------------\n* TRACE version\n****************") 
#endif

    char buf[4096], *p = buf;
    va_list args;
    va_start(args, fmt);
    p += _vsnprintf(p, sizeof buf - 1, fmt, args);
    va_end(args);
    while ( p > buf   )
        *--p = '\0';
    *++p ='\0';
    strcat(buf,"\n");
    OutputDebugString(buf);
}



static BOOL read_device(HANDLE hCom, USHORT InputReportLen, BYTE* InputReport)
{
    memset( InputReport, 0, InputReportLen);
    bool found =false;
    DWORD TransBytes;
    
    //-------------------------------
    return ReadFile( hCom, InputReport, InputReportLen, &TransBytes, NULL);
}


/////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////


BOOL close_device(HANDLE &hCom)
{
    if( hCom )
    {
        CloseHandle(hCom);
        hCom = NULL;
    }
    return 1;
}


/*-------------------------------------------------------------------------------------*/
/*    Device Manage Layer                                                              */
/*  g_hUsbDevMap object contant two buff, phUsbDev is the device info ptr buffer,      */
/*  the other (aInUsed) is the index table of the device inused, Be cear, index 0      */
/*  means no device, the other value point the index of device buffer and plus 1.      */
/*  The inuse table is out-of-order!                                                   */  
/*  The up-level controled handle is the device buffer index and plus 1.               */


/*
  strKey-->KEY_ID  {1~128}
            |______Array[KEY_ID] for estimate whether new port plug device in
            |______KEY_ID - 1 == [g_DevPathIndex.pIndexÏÂ±ê]£¬{0~127}                  

   g_hUsbDevMap.phUsbDevÁ´±íÎªÉè±¸Á´±í¼ÇÂ¼ËùÓÐÒÑ²åÈëÉè±¸
   g_DevPathIndex.pIndex ÏÂ±êÎª¾ä±úºÅ£¬ÎªÉè±¸»º³å¼¯ºÏ

*/
/*-------------------------------------------------------------------------------------*/
/////////////////////////////////////////////////////////////////////////

void InitUsbDevMap()
{
    memset( &g_hUsbDevMap, 0 ,sizeof( g_hUsbDevMap ) );
}

int DevMounted(USB_PATHINFO pDevInfo)
{
    
    LP_MC_DEVICE pdev = g_hUsbDevMap.phUsbDev;
    const char * pDevPath = pDevInfo->DevicePath;
    if( pDevPath == NULL ) return 0;

    while( pdev ) 
    {
        char * szDevInfo = pdev->pPathInfo;
        if( (szDevInfo != NULL ) && strcmp(szDevInfo,pDevPath ) == 0 )
		{
			pdev->bMount = TRUE;
			return 1;
		}

        pdev = pdev->pNext; 
    }
    
	return 0;
}

void MountNode(LP_MC_DEVICE pNewDev)
{
    LP_MC_DEVICE pdev = g_hUsbDevMap.phUsbDev;
 	if( pNewDev == NULL )   return ;
    pNewDev->pNext = NULL;
    pNewDev->bMount = TRUE;


    if( pdev == NULL ) 
    {
        g_hUsbDevMap.phUsbDev = pNewDev;
    }
    else
    {        
        while( pdev && pdev->pNext ) 
        {
            pdev = pdev->pNext; 
        }
        
        pdev->pNext = pNewDev;
    }
	return ;

}

typedef struct tag_DevPathIndexBuff
{
    DWORD           count;
    LP_MC_DEVICE    pIndex[512];
}DevPathIndexBuff, * PDevPathIndexBuff;


DevPathIndexBuff  g_DevPathIndex = {0};
////////////////////////////////////////////////////////////////////
// str_path --> id
// return value: 
//       NULL  :  meanse not find such device
//       nozeor:  the device id
HANDLE GetHandle(LP_MC_DEVICE pDev, BOOL bMemRlease/*=FALSE*/)
{
    for( DWORD i=0;i<128;i++)
    {
        if( g_DevPathIndex.pIndex[i] == pDev )
        {
            if( bMemRlease ) g_DevPathIndex.pIndex[i] = NULL; 
            return (HANDLE)(i+1);
        }
    }
    return NULL;
}



HANDLE SetupHandle(MC_DEVICES * pDev)
{
    HKEY hKey = (HKEY)INVALID_HANDLE_VALUE;
    HKEY hSubKey = (HKEY)INVALID_HANDLE_VALUE;
	DWORD dw;

    DWORD dwType;
	DWORD dwSize=sizeof(DWORD);
	DWORD dwVal;

	long lReturn=RegOpenKeyEx(HKEY_CURRENT_USER,"Software",0L,KEY_ALL_ACCESS,&hKey);
    lReturn=RegCreateKeyEx(hKey,"UsbPhone",0L,NULL,REG_OPTION_VOLATILE,KEY_ALL_ACCESS,NULL,&hSubKey,&dw);

    
    BYTE aray[132];
    HANDLE hFind = (HANDLE)0;
    memset(aray,0,132);
    
    int i = 0;
    for   ( i=0;i<512;i++)   
    {   
        CHAR ValueName[512];
        BYTE DataValue[512];
        DWORD cbValueName=512;   
        DWORD cbDataValue=512;   
        if(RegEnumValue(hSubKey,i,(CHAR*)ValueName,&cbValueName,NULL,   
            &dwType,(BYTE*)DataValue,&cbDataValue)==ERROR_SUCCESS)   
        {   
            //Find device already registed
            if( memcmp(pDev->pPathInfo,ValueName,strlen(pDev->pPathInfo)) == 0 )
            {
                g_DevPathIndex.pIndex[i] = pDev;
                hFind =(HANDLE)(*(DWORD *)DataValue);
                dwVal = *(DWORD *)DataValue;
            }
            if(hFind == (HANDLE)0 && dwType == 4 )
            {
                aray[*(DWORD *)DataValue] = 1; 
            }
        }
        else 
            break;
    }

    if( hFind == (HANDLE)0 && i<511)
    {
        for(i=1;i<129;i++)
        {
            if( aray[i] == 0 )
            {
                dwVal = i;
                lReturn=RegSetValueEx(hSubKey,pDev->pPathInfo,0L,REG_DWORD,\
                    (const BYTE *) &dwVal,sizeof(DWORD));
                //add new device to index table
                g_DevPathIndex.pIndex[i-1] = pDev;
                break;
            }
        }
    }

    g_DevPathIndex.count = i;

    if (hSubKey != (HKEY)INVALID_HANDLE_VALUE) RegCloseKey(hSubKey);
    if( hSubKey != (HKEY)INVALID_HANDLE_VALUE  ) RegCloseKey(hKey);

    return (HANDLE)dwVal;

}


LP_MC_DEVICE GetUsbDviceHandle(HANDLE hDev)
{
    LP_MC_DEVICE pdev = g_hUsbDevMap.phUsbDev;
    if (hDev == 0) hDev = DEFALT_DEV;
    if( (INT)hDev == 0 || (INT)hDev >= 512 ||  (int)hDev > (int)g_DevPathIndex.count )
        return NULL;

    if(  (hDev != DEFALT_DEV) && (BROADCAST_HANDLE != hDev ))
    {
        
        HANDLE hDevice = g_DevPathIndex.pIndex[(INT)hDev - 1];
        
        if( hDevice == NULL )return NULL;
        
        while( pdev &&  (HANDLE)pdev != hDevice ) 
        {
            pdev = pdev->pNext; 
        }
    }
    return pdev;  //value maybe NULL yet
}

LP_MC_DEVICE GetUsbDviceHandle(LP_MC_DEVICE pDev)
{
    if( pDev )
    {
        return pDev->pNext;
    }
    return NULL;
}

extern "C" EXP_FUN HANDLE FindUsbDvice(HANDLE hdev)
{
    LP_MC_DEVICE pdev;
    pdev = GetUsbDviceHandle(hdev);
    return GetHandle(pdev);
}


extern "C" EXP_FUN HANDLE FindNextUsbDvice(HANDLE hdev)
{
    LP_MC_DEVICE pdev;
    if( hdev == NULL )
        pdev = g_hUsbDevMap.phUsbDev;
    else 
    {
        pdev = GetUsbDviceHandle(hdev);
        if( pdev ) pdev = GetUsbDviceHandle(pdev);
    }
    return GetHandle(pdev);
}

////////////////////////////////////////////////////////////////////
// id --> str_path --> handle
HANDLE MountDev(USB_PATHINFO pDevInfo, INT ChipId, HANDLE hRead, HANDLE hWrite)
{
    const HID_DRIVER* pdrv = LoadDriver( ChipId );
    if (pdrv == NULL) return INVALID_HANDLE_VALUE;

    DWORD Id;
    MC_DEVICES* pFindDev = new MC_DEVICES; 
    memset(pFindDev,0,sizeof(MC_DEVICES));
    *(HID_DRIVER*)pFindDev = *pdrv;

    pFindDev->hRead = hRead;
    pFindDev->hWrite = hWrite;
    pFindDev->hInBuff = CreateQunue(2048);
    pFindDev->hOutBuff = CreateQunue(2048);
    pFindDev->OvRd.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    pFindDev->OvWr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    pFindDev->hEvtDemount = CreateEvent(NULL, TRUE, FALSE, NULL);
    pFindDev->OvWr.Offset = 0;
    pFindDev->OvWr.OffsetHigh = 0;

  
	pFindDev->hReadThread = CreateThread(NULL,1024*16, pFindDev->pfnxThreadRead,pFindDev,0,&Id);
	
	pFindDev->bTaskRun = 2;

	int szPathLen = strlen(pDevInfo->DevicePath)+16;
	pFindDev->pPathInfo = new char[szPathLen];    
	memset( pFindDev->pPathInfo, 0 ,szPathLen );
	strcpy(pFindDev->pPathInfo, pDevInfo->DevicePath);

	pFindDev->pDecBuff = new BYTE [g_hUsbDevMap.DecodeBufSize];
	memset(pFindDev->pDecBuff,0,g_hUsbDevMap.DecodeBufSize);

    MountNode( pFindDev );    
    delete pDevInfo;

    return SetupHandle(pFindDev);
}

int UnmountDev(MC_DEVICES* pFindDev)
{
    if( pFindDev == NULL ) return 0;
    SetEvent( pFindDev->hEvtDemount ); //Exit read thread
    while( pFindDev->bTaskRun )
    {
        Sleep(20);
    }

    ReleaseQunue( pFindDev->hInBuff );
    ReleaseQunue( pFindDev->hOutBuff );
    close_device( pFindDev->OvRd.hEvent );
    close_device( pFindDev->OvWr.hEvent );
    close_device( pFindDev->hEvtDemount );

    close_device( pFindDev->hRead );
    close_device( pFindDev->hWrite );
    CloseHandle(pFindDev->hReadThread);
	delete (pFindDev->pPathInfo);
	delete (pFindDev->pDecBuff);
    delete (pFindDev);

    return 1;
}

void RemountDev()
{
    LP_MC_DEVICE pdev = g_hUsbDevMap.phUsbDev;
    while( pdev ) 
    {
        pdev->bMount = FALSE;
        pdev = pdev->pNext; 
    }
	return ;
}


void WaitUnmaountAll(void)
{
    LP_MC_DEVICE pDev = g_hUsbDevMap.phUsbDev;

    while( pDev ) 
	{
        int timeout = 200;
		while( timeout-- && pDev && pDev->bTaskRun )
		{
			Sleep(10);
			continue;
		}
        pDev = pDev->pNext; 
	}

	Sleep(100);

    pDev = g_hUsbDevMap.phUsbDev;
    while( pDev ) 
	{
        g_hUsbDevMap.phUsbDev = pDev->pNext;
        UnmountDev(pDev);
        //&pDev - &g_DevPathIndex.pIndex[0]
        pDev = g_hUsbDevMap.phUsbDev;
	}	
}

void CheckRemovedDev(void)
{
    LP_MC_DEVICE pDev = g_hUsbDevMap.phUsbDev;
    if( pDev == NULL ) return;
    while(pDev && pDev->pNext ) 
	{
        while( pDev->pNext && pDev->pNext->bMount == 0 )
		{
            LP_MC_DEVICE pDevNext = pDev->pNext->pNext;
			SendDetachMsgToParent(GetHandle(pDev->pNext, TRUE));
			UnmountDev(pDev->pNext);
            pDev->pNext= pDevNext ;
		}
        pDev = pDev->pNext;
	}

    pDev = g_hUsbDevMap.phUsbDev;

    if( pDev && pDev->bMount == 0 )
	{
		SendDetachMsgToParent(GetHandle(pDev, TRUE));
        g_hUsbDevMap.phUsbDev = pDev->pNext;
		UnmountDev(pDev);
	}
}

//-------------------------------------------------------------------------------------/


///////////////////////////////////////////////////////////////////////////////////////
//

HANDLE  DetectHidDevice()
{
    HANDLE   hRead , hWrite ;
    USHORT InputReportLen = 0, OutputReportLen = 0;
    USB_PATHINFO pinfo ;
    int ChipId = CHIP_UNKOWN;
    pinfo = (USB_PATHINFO)Get_device(hWrite, &ChipId,\
        &InputReportLen, &OutputReportLen, MC_HID_WRITE_WITH_INFO);
    if (pinfo== NULL || ChipId == CHIP_UNKOWN )
    {
        return NULL;
        hWrite = NULL;
    }    
    else 
	{
        hRead = CreateFile((LPCSTR)pinfo->DevicePath , GENERIC_READ, \
            FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, \
            FILE_FLAG_OVERLAPPED, NULL); 
        
		/*
		if (!Get_device(hRead, &InputReportLen, &OutputReportLen, MC_HID_READ) ) 
    {
        CloseHandle(hWrite);
        return NULL;
    }*/
    }

	HANDLE id = MountDev(pinfo, ChipId, hRead, hWrite);
	if( id == NULL )
	{
        CloseHandle(hWrite);
        CloseHandle(hRead);
		delete (pinfo);
	}

    return (HANDLE)id;

}

///////////////////////////////////////////////////////////////////////////////////////////
// exported interface function

EXP_FUN HANDLE InitUsbDev(INT nDecBuffSize,HWND hWnd, LPTHREAD_START_ROUTINE pCallBackReadDec)
{
    // TODO: Add your control notification handler code here
    //UsbPnpDevDetect((DWORD)hWnd,0);
	if( !hWnd || !IsWindow(hWnd))
        return NULL;

    ResetEvent(g_hUsbDevMap.hEVTUsbExit);
    if(g_hUsbDevMap.hEVTUsbExit == NULL )
    {
	    InitUsbDevMap();
        g_hUsbDevMap.hEVTUsbExit = CreateEvent(NULL, TRUE, FALSE, NULL);
    }
	g_hUsbDevMap.DecodeBufSize = nDecBuffSize;	
	g_hUsbDevMap.pCallbackDec = pCallBackReadDec;
    g_hUsbDevMap.hNotify = hWnd;

    InitUsbPnpMsgWnd(hWnd,NULL);
    return (HANDLE)g_hUsbDevMap.hEVTUsbExit;
}


EXP_FUN void UnInitUsbDev(HANDLE hUsbDev)
{
    KillTimer(NULL,73177);
	SetEvent(g_hUsbDevMap.hEVTUsbExit);
	WaitUnmaountAll();
	UnInitUsbPnpMsgWnd();
   	UnRegisterPnpMessage( );
    CloseHandle(g_hUsbDevMap.hEVTUsbExit);
    g_hUsbDevMap.hEVTUsbExit = NULL;

    //UninitUsbDev(hUsbDev);
}


EXP_FUN INT ReadUSBDev(HANDLE hDevice, void * pbuf, int dwSize,\
               int timeout,DWORD * pErr)
{
    INT ret = -1;
    MC_DEVICES * pDev = GetUsbDviceHandle(hDevice); 
    if( pDev  ) 
        return pDev->pfnxHidRead(hDevice,pbuf,dwSize,timeout,pErr);
    return ret;
}

void DelayUs(__int64 Us)
{
    LARGE_INTEGER CurrTicks, TicksCount; 

    QueryPerformanceFrequency(&TicksCount);
    QueryPerformanceCounter(&CurrTicks); 

    TicksCount.QuadPart = TicksCount.QuadPart * Us / 1000000i64;
    TicksCount.QuadPart += CurrTicks.QuadPart; 

    while(CurrTicks.QuadPart<TicksCount.QuadPart)
         QueryPerformanceCounter(&CurrTicks);
}


EXP_FUN INT WriteUSBDev(HANDLE hDevice , void* pvbuf, int dwSize, DWORD * err)
{
    INT ret = -1;
	MC_DEVICES * pDev = GetUsbDviceHandle(hDevice);
    if( pDev  ) 
        return pDev->pfnxHidWrite(hDevice , pvbuf, dwSize,  err);
    return ret;
}

// dumy interface for compitate audio version
EXP_FUN void PrintDeviceConfigurations(HANDLE hDevice)
{
    //Do nothing
}


EXP_FUN INT USBRecord(HANDLE hUsbDev,void *pbuf,int dwSize,\
              int timeout,DWORD * pErr)
{
    return 1;
}

EXP_FUN INT USBReplay(HANDLE hUsbDev,void *pbuf,int dwSize, \
                 int timeout, DWORD * pErr)
{
    return 1;
}

EXP_FUN INT USBHaltTransfer(HANDLE hDevice,int Piple_ID)
{
    return 1;
}

EXP_FUN VOID * GetDecodeBuff(HANDLE hDev)
{
    MC_DEVICES * pdev = GetUsbDviceHandle(hDev);
    return pdev->pDecBuff;
}

EXP_FUN INT GetDeviceStatus(void)
{
	LP_MC_DEVICE  pdev = g_hUsbDevMap.phUsbDev;
    int cnt = 0;
	
	while( pdev->pNext )
	{
	    pdev = pdev->pNext;
		cnt++;
	}
	return cnt;
}


///////////////////////////////////////////////////////////////////////////////////////////
// exported interface function end

#if 0
#include "USB.h"
#ifdef _DEBUG
#include<iostream>
using namespace std;
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

VOID USB_init()
{
    char sHCD[32];
    int i,j,PortNum;
    HANDLE hHCD,hHUB,hDevice;
    PCHAR rootHubName,DeviceName;
    PCHAR sHUB,sDevice;
    PUSB_NODE_INFORMATION HubInfo;
    PUSB_NODE_CONNECTION_INFORMATION connection;
    unsigned long lResult,nBytes;
    DefNum=0;
    for(i=0;i<32;i++)
    {
        wsprintf(sHCD, "\\\\.\\HCD%d", i);
        hHCD=CreateFile(sHCD,GENERIC_WRITE + GENERIC_READ, FILE_SHARE_WRITE + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
        if(hHCD==INVALID_HANDLE_VALUE)
            break;
        
        rootHubName=GetHubName(hHCD);
        sHUB=new CHAR[strlen(rootHubName)+strlen("\\\\.\\")+1];
        strcpy(sHUB,"\\\\.\\");
        strcpy(sHUB + strlen("\\\\.\\"), rootHubName);
        delete (rootHubName);
        cout<<sHUB<<endl;
        hHUB=CreateFile(sHUB,
            GENERIC_WRITE + GENERIC_READ,
            FILE_SHARE_WRITE + FILE_SHARE_READ, 
            NULL, 
            OPEN_EXISTING, 
            0, 
            NULL);
        delete (sHUB);
        HubInfo=new USB_NODE_INFORMATION;//(malloc(sizeof(USB_NODE_INFORMATION)));
        lResult=DeviceIoControl(hHUB,
            IOCTL_USB_GET_NODE_INFORMATION,
            HubInfo,
            sizeof(USB_NODE_INFORMATION),
            HubInfo,
            sizeof(USB_NODE_INFORMATION),
            &nBytes,
            NULL);
        PortNum=HubInfo->u.HubInformation.HubDescriptor.bNumberOfPorts;
        for(j=0;j<PortNum;j++)
        {
            nBytes=sizeof(USB_NODE_CONNECTION_INFORMATION)+sizeof(USB_PIPE_INFO)*30;
            connection= (PUSB_NODE_CONNECTION_INFORMATION)new BYTE[nBytes];//malloc(nBytes);
            connection->ConnectionIndex=j;
            lResult = DeviceIoControl(hHUB,
                IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
                connection,
                nBytes,
                connection,
                nBytes,
                &nBytes,
                NULL);
            if (connection->ConnectionStatus == DeviceConnected)
            {
                DeviceName=GetDeviceName(hHUB,j);
                cout<<DeviceName<<endl;
                sDevice=new CHAR[(strlen(DeviceName)+strlen("\\\\.\\")+1)];
                strcpy(sDevice,"\\\\.\\");
                strcat(sDevice, DeviceName);
                delete (DeviceName);
                hDevice=CreateFile(sDevice,
                    GENERIC_WRITE + GENERIC_READ,
                    FILE_SHARE_WRITE + FILE_SHARE_READ, 
                    NULL, 
                    OPEN_EXISTING, 
                    0, 
                    NULL);
                Devices[DefNum++]=hDevice;
                delete (sDevice);
            }
            delete (connection);
        }
        delete (HubInfo);
        CloseHandle(hHUB);
        CloseHandle(hHCD);
    }
    DefNum=0;
}

USB_unInit()
{
    for(int i=0;i<DefNum;i++)
        CloseHandle(Devices);
}
PCHAR GetHubName(HANDLE HostController)
{
    BOOL                success;
    ULONG              nBytes;
    USB_ROOT_HUB_NAME  rootHubName;
    PUSB_ROOT_HUB_NAME  rootHubNameW;
    PCHAR              rootHubNameA;

    rootHubNameW = NULL;
    rootHubNameA = NULL;
  success = DeviceIoControl(HostController,
                              IOCTL_USB_GET_ROOT_HUB_NAME,
                              0,
                              0,
                              &rootHubName,
                              sizeof(rootHubName),
                              &nBytes,
                              NULL);

    if (!success)
    {
        goto GetRootHubNameError;
    }

    nBytes = rootHubName.ActualLength;

    rootHubNameW =(PUSB_ROOT_HUB_NAME) new BYTE[nBytes];

    if (rootHubNameW == NULL)
    {

        goto GetRootHubNameError;
    }

    success = DeviceIoControl(HostController,
                              IOCTL_USB_GET_ROOT_HUB_NAME,
                              NULL,
                              0,
                              rootHubNameW,
                              nBytes,
                              &nBytes,
                              NULL);

    if (!success)
    {
      goto GetRootHubNameError;
    }

    rootHubNameA = WideStrToMultiStr(rootHubNameW->RootHubName);
    delete (rootHubNameW);

    return rootHubNameA;


GetRootHubNameError:
    if (rootHubNameW != NULL)
    {
        delete (rootHubNameW);
        rootHubNameW = NULL;
    }

    return NULL;
}
PCHAR WideStrToMultiStr(PWCHAR WideStr)
{
    ULONG nBytes;
    PCHAR MultiStr;
    nBytes = WideCharToMultiByte(CP_ACP,0,WideStr,-1,NULL,0,NULL,NULL);
    if (nBytes == 0)
        return NULL;

    MultiStr = new CHAR[nBytes];
    if (MultiStr == NULL)
        return NULL;
    nBytes = WideCharToMultiByte(CP_ACP,0,WideStr,-1,MultiStr,nBytes,NULL,NULL);
    if (nBytes == 0)
    {
        delete (MultiStr);
        return NULL;
    }
    return MultiStr;
}
PCHAR GetDeviceName(HANDLE Hub, ULONG ConnectionIndex)
{
    BOOL success;
    ULONG nBytes;
    USB_NODE_CONNECTION_NAME nodeName;
    PUSB_NODE_CONNECTION_NAME nodeNameW=NULL;
    PCHAR nodeNameA=NULL;
    nodeName.ConnectionIndex=ConnectionIndex;
    success = DeviceIoControl(Hub,
                              IOCTL_USB_GET_NODE_CONNECTION_NAME,
                              &nodeName,
                              sizeof(nodeName),
                              &nodeName,
                              sizeof(nodeName),
                              &nBytes,
                              NULL);
    if(!success)
        goto GetDeviceNameError;
    nBytes=nodeName.ActualLength;
    if(nBytes<sizeof(nodeName))
        goto GetDeviceNameError;
    nodeNameW=(PUSB_NODE_CONNECTION_NAME) new BYTE[nBytes];
    nodeNameW->ConnectionIndex=ConnectionIndex;
    success = DeviceIoControl(Hub,
                              IOCTL_USB_GET_NODE_CONNECTION_NAME,
                              nodeNameW,
                              nBytes,
                              nodeNameW,
                              nBytes,
                              &nBytes,
                              NULL);
    if(!success)
        goto GetDeviceNameError;
    nodeNameA=WideStrToMultiStr(nodeNameW->NodeName);
    return nodeNameA;
GetDeviceNameError:
    if(nodeNameW)
        delete (nodeNameW);
    return NULL;
}
PCHAR GetDriverKeyName(HANDLE Hub, ULONG ConnectionIndex)
{
    BOOL                                success;
    ULONG                              nBytes;
    USB_NODE_CONNECTION_DRIVERKEY_NAME  driverKeyName;
    PUSB_NODE_CONNECTION_DRIVERKEY_NAME driverKeyNameW;
    PCHAR                              driverKeyNameA;
    driverKeyNameW = NULL;
    driverKeyNameA = NULL;
    driverKeyName.ConnectionIndex = ConnectionIndex;
    success = DeviceIoControl(Hub,
                              IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
                              &driverKeyName,
                              sizeof(driverKeyName),
                              &driverKeyName,
                              sizeof(driverKeyName),
                              &nBytes,
                              NULL);

    if (!success)
        goto GetDriverKeyNameError;
    nBytes = driverKeyName.ActualLength;
    if (nBytes < sizeof(driverKeyName))
        goto GetDriverKeyNameError;
    driverKeyNameW = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)new BYTE[nBytes];
    if (driverKeyNameW == NULL)
        goto GetDriverKeyNameError;
    driverKeyNameW->ConnectionIndex = ConnectionIndex;
    success = DeviceIoControl(Hub,
                              IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME,
                              driverKeyNameW,
                              nBytes,
                              driverKeyNameW,
                              nBytes,
                              &nBytes,
                              NULL);
    if (!success)
        goto GetDriverKeyNameError;
    driverKeyNameA = WideStrToMultiStr(driverKeyNameW->DriverKeyName);
    delete (driverKeyNameW);

    return driverKeyNameA;


GetDriverKeyNameError:
    if (driverKeyNameW != NULL)
    {
        delete (driverKeyNameW);
        driverKeyNameW = NULL;
    }

    return NULL;
}
#endif


EXP_FUN void UsbPnpDevDetect(DWORD wParam, DWORD lParam)
{
}

EXP_FUN const char * GetStatusString(DWORD dwStatus)
{
    return NULL;
}

extern int DrvGetDeviceId(HANDLE hDevice )
{
	MC_DEVICES * pDev = GetUsbDviceHandle(hDevice);
    if( pDev != NULL )
        return pDev->nDevTypeId;
    return CHIP_UNKOWN;
}